#include <stdio.h>
#include <stdlib.h> // ces deux là, sont toujours utiles

#include <string.h>	// manip des chaines de caractères
#include <ctype.h>	// types C
#include <getopt.h>	// parseur d'arguments

#include "assembleur.h"	
	// entêtes des fonctions et structures de données globales
#include "instructions.h"
	// codage d'instructions


// variables globales
instruction_intermediaire1 RI[TMEM];
int nerreurs =0 ; //nombre d'erreurs
int c_instructions = 0; /* indice courant de la memoire*/

// Lire les descriptifs des fonctions dans le fichier "assembleur.h"

/**Fonctions utilitaires*/

///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////

void init_RI()
{
 int i;
 for(i=0; i< TMEM; i++)
 {
  RI[i].ligne_source = 0;
  RI[i].instruction =-1;
  RI[i].operande=0;
  memset(RI[i].toperande, 0, TOPERANDE);
  RI[i].fini=0;
  RI[i].oqp=0;
 }
}


///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////

/**
 * \todo gerer les lignes de taille quelconque (GNU getline() plutot que fgets ?)
 * \bug verifier que les pointeurs sont non nuls
 */
int lire_source(FILE *src, instruction_source *is)
{
  char ligne[MAX_LINE];
  char c;
  int i;

  if(feof(src))
  {
    return 1; /*On quitte s'il n'y a plus rien a lire*/
  }

  if((c = fgetc(src)) == '*') /*Si la ligne commence par un * c'est un commentaire*/
  {
    while (!feof(src) && fgetc(src) != '\n') /*on va a la ligne suivante*/
    {
    }
    return 2; /* on renvoie qu'il s'agit d'un commentaire*/
  }
  if(c== '\n') /* traitement des lignes blanches */
  {
       return 2; /* on renvoie qu'il s'agit d'un commentaire meme si ce n'est pas vrai*/
  }
  else
  {
    ungetc(c, src);
    fgets(ligne, MAX_LINE, src);
    if(isblank(c))
    {
    /** \bug ces constantes (TINSTRUCTION, TOPERANDE) ne devraient pas être en dur */
      if(sscanf(ligne, " %7s %36s", (is->instruction), is->operande ) !=2 )
      {
        fprintf(stderr, "Erreur1 lors de la lecture du fichier source\n");
        exit(EXIT_FAILURE);
      }
    }
    else
    {
    /** \bug ces constantes (TSYMBOLE, TINSTRUCTION, TOPERANDE) ne devraient pas être en dur */
      if(sscanf(ligne, "%30s %7s %36s", is->nom, is->instruction, is->operande ) != 3)
      {
        fprintf(stderr, "Erreur2 lors de la lecture du fichier source\n");
        exit(EXIT_FAILURE);
      }
    }

    for(i=0; i<TINSTRUCTION; i++)
    {
      is->instruction[i]=toupper(is->instruction[i]);
    }

    return 0;
  }
}

///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////


int indice_instruction(char *instruction)
{int I;
for(I=0;I<NINST;I++)
  {
  if(strcmp(instruction, table_code_instruction[I].nom)==0)return (I);
  }
fprintf(stderr,"instruction non reconnue");
nerreurs++;
return (-1);
}

///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////


int decouper_operande(const char *operande, char *symbole, int *val)
{
  int i = 0;
  *val=0;

  if(!operande || !symbole) return -1;

  if(isalpha(operande[i])){ symbole[i] = operande[i];i++;} ;
  while(operande[i] && i < TSYMBOLE)
  {
    if(isalnum(operande[i])) symbole[i] = operande[i];
    else
    {
      *val = (int)strtol(&(operande[i]), (char**)NULL, 0);
      i = TSYMBOLE;
    }
    i++;
  }
  return 0;
}
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////

int initialiser_table_symbole()
{
  memset(table_symbole.T, 0, sizeof(table_symbole.T));
  table_symbole.index = 0;
  return 0;
}

///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////


int ajouter_symbole(const char *symbole, int adresse)   //modif detection de symbole duplique  CT
{
  int i;
  if(!symbole || !strncmp(symbole, "", TSYMBOLE))
  {
    fprintf(stderr,"Erreur : nom du symbole %s (%p) invalide\n", symbole, symbole);
    return -1;
  }
/*  else if(adresse < 0 || adresse > TMEM)   //FAUX CT 25nov09
  {
    fprintf(stderr,"Erreur : l'adresse du symbole %s (%d) est invalide\n", symbole, adresse);
    return -2;
  }
  */
  else if(table_symbole.index >= TMEM)
  {
    fprintf(stderr,"Erreur : table des symboles pleine\n");
    return -3;
  }
  else {                                              //test CT
      for(i=0;i<table_symbole.index;i++)
         {
          if (strncmp(table_symbole.T[i].nom,symbole, TSYMBOLE)== 0 )
            {
             fprintf(stderr," ERREUR symbole %s existe deja\n",symbole);
             nerreurs++;
             return -4;
             }
         }
       }
//autrement
{
    strncpy(table_symbole.T[table_symbole.index].nom, symbole, TSYMBOLE);
    table_symbole.T[table_symbole.index].adresse = adresse;
    table_symbole.index++;
    return 0;
  }
}

///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////


int obtenir_adresse_symbole(char *symbole)
{
  int i;

  for(i=0; i<TMEM; i++)
  {
    if( strcmp(table_symbole.T[i].nom, symbole) == 0 )
    {
      return table_symbole.T[i].adresse;
    }
  }
  return -1;
}

///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////


int obtenir_valeur_operande(const char* operande)
{
#define RIEN 0
#define PLUS 1
#define MOINS 2
//pour les + et - unaires et binaires
int i;     //pointeur de chaine
int j;
char c;    //caractere lu
int valeur; //valeur en cours de calcul
int valeur1; //temporaire de calcul
int fn;     //traitement des + et - unaires et binaires de gauche a droite
int post_process; // booléen pour faire l'ancien label 'suite4'

char symbole[TSYMBOLE]="";

 // premier caractere

 i=0; valeur=0; fn=RIEN;  valeur1=0;
 c=operande[i];

  //n'importe quel caractere


for(;;)	// ancien label  suite3:
{
	c=operande[i];
	post_process=0;
	switch(c){
		
		case '*':
			valeur1= c_instructions;
			i++; 
			post_process=1;
			break;
		case '+':
			fn=PLUS; 
			i++;
			break;
		case '-':
			fn=MOINS;
			i++;
			break;
		case '$':
			valeur1=0;
			i++; //depasser le $        ///debut essai2
			while((isdigit(operande[i]))||((operande[i]>='a')&&(operande[i]<='f'))||((operande[i]>='A')&&(operande[i]<='F')))
				{
				if (isdigit(operande[i]))
					{
					valeur1=valeur1*16+operande[i]-'0';
	 			 	i++;
	  			 	}
	 			 if ((operande[i]>='a')&&(operande[i]<='f'))
	 			 	{
					valeur1=valeur1*16+operande[i]-'a'+10;
	 			 	i++;
	  			 	}
	 			 if ((operande[i]>='A')&&(operande[i]<='F'))
	 			 	{
					valeur1=valeur1*16+operande[i]-'A'+10;
		 			 i++;
		  			 }
				post_process=1;
		    		}
		case '\'':
			{
			i++;
			if (operande[i]== '\\' )
				{
				i++;
				c= operande[i];
				switch(c)
			            	{
					case 'w':
						valeur1=' ';
						i++;
						break;   //blanc
					case 't':
						valeur1='\t';
						i++;
						break;
					case '\0':
						valeur1='\0';
						i++;
						break;
					case '\n':
						valeur1='\n';
						i++;
						break;
					case '\\' :
						valeur1='\\';
						i++;
						break;
					default :
						nerreurs++;
					}
				}
			else
				{
				valeur1=operande[i];
				i++;
				}
			if (operande[i]!='\'')
				{
				fprintf(stderr,"%c erreur de constante litterale \n",valeur1);
				nerreurs++ ;
				}
			i++;
			post_process=1;
			}



	
		case ' ':
		case '\n':
		case 0:
			return valeur;	//fin de champ ou de ligne

		default:
			if (isdigit(c)) //valeur decimale
				{
				valeur1=0;
				while(isdigit(operande[i]))
					{
					valeur1=valeur1*10+operande[i]-'0';
					i++;
					}
				post_process=1;
				}
			else
				if (isalpha(c)){
					j=0;
					while(isalnum(c=operande[i]))
						{
						symbole[j]=operande[i];
						i++;j++;
						}
					valeur1=obtenir_adresse_symbole(symbole);
					if (valeur1==-1) 
						{fprintf(stderr,"erreur : symbole '%s' pas encore defini", symbole);exit(EXIT_FAILURE);}
					post_process=1;
					}
				else
					if(c != ' ' && c != '\n' && c != 0)
						return 1;//test

			break;
		} // fin switch

	if(post_process){
		if (fn==PLUS)  valeur = valeur+valeur1;
		if (fn==MOINS) valeur = valeur-valeur1;
		if (fn==RIEN)  valeur = valeur1;
		fn=RIEN; valeur1=0;  //remise a zero des differents sous champs
		memset(symbole,0,TSYMBOLE);
		}

	 // passer au champ suivant
	}// fin for
}

///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////


/*Fonctions d'affichage*/
void afficher_table_symbole(FILE *sortie)
{
  int i;

  fprintf(sortie, "Table des symboles (%d symboles)\n", table_symbole.index);
  for(i=0; i < TMEM;i++)
  {
    if(strcmp(table_symbole.T[i].nom, "") || table_symbole.T[i].adresse )
    {
      fprintf(sortie, "%d : %s %d\n", i, table_symbole.T[i].nom, table_symbole.T[i].adresse);
    }
  }
}
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////


void afficher_RI(FILE *sortie)
{
  int i;
  fprintf(sortie, "Representation intermediaire\n");
  for(i=0; i < TMEM;i++)
    {
      fprintf(sortie, "MEM[%03d] : %d %d %s %d %d (definie ligne %d)\n", \
        i, \
        RI[i].instruction, \
        RI[i].operande, \
        RI[i].toperande, \
        RI[i].oqp,       \
        RI[i].fini,      \
        RI[i].ligne_source);
    }
}

///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
/*Passes refonte totale CT */
/** \todo harmoniser les messages d'erreur*/
int passe1(FILE *src)
{
  instruction_source instruction = {"", "",""};

  int decalage = 0; /* incrementation compteur d'implantation memoire dû a l'instruction (sa taille)*/
  int compteur_ligne = 1;
  int adresse_symbole = 0;
  int valeur_retour_source = 0;
  int c_instructions1; /* adresse d'implantation mise dans la table des symboles CT4dec*/

  memset(RI, 0, sizeof(RI));

  do
  {
    memset(&instruction, 0, sizeof(instruction));
    while((valeur_retour_source=lire_source(src, &instruction)) == 2)//commentaire
    {
      compteur_ligne++;
    }
    if(valeur_retour_source != 0 && valeur_retour_source != 2)//EOF par exemple
    {
       fprintf(stderr, "Erreur lors de la lecture de l'instruction ligne %d (%s, %d)\n", \
            compteur_ligne, instruction.nom, c_instructions);
          exit(EXIT_FAILURE);
    }

#ifdef DEBUG
   fprintf(stderr, "Source     S%d : [ %s | %s | %s ]\n", \
      c_instructions, \
      instruction.nom, \
      instruction.instruction, \
      instruction.operande);
#endif
    c_instructions1=c_instructions;
    if(!strncmp(instruction.instruction, "ORG", 3))
    {
      c_instructions = obtenir_valeur_operande(instruction.operande);
      c_instructions1 = c_instructions;
      decalage = 0;
    }
    else if(!strncmp(instruction.instruction, "RMW", 3))
    {
      decalage = obtenir_valeur_operande(instruction.operande);
      decalage = abs(decalage); /*garde fou a documenter*/

      if(c_instructions >= TMEM || c_instructions < 0) RI[c_instructions].ligne_source = compteur_ligne;//????CT

      c_instructions1 = c_instructions;  //ct4dec
      while (decalage > 0)
      {
        if(c_instructions >= TMEM || c_instructions < 0)
        {
          fprintf(stderr, "Erreur ligne %d : %d est en dehors de la memoire de la machine (%d)\n", compteur_ligne, c_instructions, TMEM);
          exit(EXIT_FAILURE);
        }
        else if(RI[c_instructions].oqp != 0)
        {
          fprintf(stderr, "Erreur ligne %d : Tentative de reecriture sur de la memoire deja initialisee\n", compteur_ligne);
          exit(EXIT_FAILURE);
        }
        else
        {
          RI[c_instructions].oqp = 1;
          c_instructions++;
          decalage--;
        }
      }
    }
    else if(!strncmp(instruction.instruction, "FCW", 3)) //form constant word
    { int val;
      val = obtenir_valeur_operande(instruction.operande);
      val = abs(val); /*garde fou a documenter pas de valeur negative*/

      if(c_instructions >= TMEM || c_instructions < 0) RI[c_instructions].ligne_source = compteur_ligne;//????CT

      {
        if(c_instructions >= TMEM || c_instructions < 0)
        {
          fprintf(stderr, "Erreur ligne %d : %d est en dehors de la memoire de la machine (%d)\n", compteur_ligne, c_instructions, TMEM);
          exit(EXIT_FAILURE);
        }
        else if(RI[c_instructions].oqp != 0)
        {
          fprintf(stderr, "Erreur ligne %d : Tentative de reecriture sur de la memoire deja initialisee\n", compteur_ligne);
          exit(EXIT_FAILURE);
        }
        else
        {
          RI[c_instructions].oqp = 1;
          RI[c_instructions].operande=val;
          RI[c_instructions].fini=1;//RI[c_instructions].fini=1;//test ct le8dec
          RI[c_instructions].instruction=FCWT;//testCT le 11dec
          RI[c_instructions].ligne_source=compteur_ligne;
          c_instructions1 = c_instructions;  //ct4dec
          c_instructions++;
#ifdef DEBUG
          fprintf(stderr,"FCW  c_instructions= %d, val=%d\n",c_instructions1,RI[c_instructions1].operande);//test CT
#endif
        }
      }
    }
    else if(!strncmp(instruction.instruction, "EQU", 3))
    {
      adresse_symbole = obtenir_valeur_operande(instruction.operande);

      if(ajouter_symbole(instruction.nom, adresse_symbole) )
      {
        fprintf(stderr, "Erreur ligne %d lors de l'ajout du symbole (%s, %d)\n", compteur_ligne, instruction.nom, adresse_symbole);
        exit(EXIT_FAILURE);
      }
      decalage = 0;
    }
    else if(!strncmp(instruction.instruction, "END", 3))
    {
    /*operande inutile?*/
    }
    else
    { int tmp;
      decalage = 1;
      if(c_instructions >= TMEM || c_instructions < 0)
      {
        fprintf(stderr, "Erreur ligne %d : %d est en dehors de la memoire de la machine (%d)\n", compteur_ligne, c_instructions, TMEM);
        exit(EXIT_FAILURE);
      }
      if(RI[c_instructions].oqp != 0)
      {
        fprintf(stderr, "Erreur ligne %d : Tentative de reecriture sur de la memoire deja initialisee\n", compteur_ligne);
        exit(EXIT_FAILURE);
      }
      tmp= indice_instruction(instruction.instruction);
      if(tmp==-1){fprintf(stderr,"Instruction %s inexistante \n",instruction.instruction); nerreurs++;}

      RI[c_instructions].oqp =1;
      if (instruction.operande[0]=='#')                             //detection immediat
      {memmove(instruction.operande,&(instruction.operande[1]),TOPERANDE-1);
       RI[c_instructions].instruction =table_code_instruction[tmp].immediat;
      }
      else if ((instruction.operande[strlen(instruction.operande)-2]==',')&&(toupper(instruction.operande[strlen(instruction.operande)-1])=='X'))
      {instruction.operande[strlen(instruction.operande)-2]='\0';
      RI[c_instructions].instruction =table_code_instruction[tmp].indexe ; // detection indexe
      }
      else if ((instruction.operande[0]=='[')&&(instruction.operande[strlen(instruction.operande)-1]==']'))
      {memmove(instruction.operande,&(instruction.operande[1]),TOPERANDE-1);
      instruction.operande[strlen(instruction.operande)-1]='\0';
      RI[c_instructions].instruction =table_code_instruction[tmp].indirect;  // detection indirect
      }
      else
      {RI[c_instructions].instruction =table_code_instruction[tmp].direct;}
      RI[c_instructions].ligne_source = compteur_ligne;

      if((RI[c_instructions].instruction == -1) ||  (RI[c_instructions].instruction ==ND))
      {
        fprintf(stderr, "Erreur ligne %d : instruction %s non reconnue ou mode inconnu\n", \
        compteur_ligne, instruction.instruction);
       // exit(EXIT_FAILURE);
       nerreurs++;
      }
      memcpy(RI[c_instructions].toperande,&(instruction.operande),TOPERANDE);  //recopie operande

    }

    /*Ajouter un symbole/label/etiquette. NB ; ne s'applique pas a EQU*/
    if(strcmp(instruction.nom, "") && strncmp(instruction.instruction, "EQU", 3))
    {
      if(ajouter_symbole(instruction.nom, c_instructions1)) //ct4dec
      {
        fprintf(stderr, "Erreur ligne %d lors de l'ajout du symbole (%s, %d)\n", \
          compteur_ligne, instruction.nom, c_instructions);
       // exit(EXIT_FAILURE);
       nerreurs++;
      }
    }

#ifdef DEBUG
    fprintf(stderr,"T%d , source %d,operande %s,instructon %d\n",c_instructions,\
    RI[c_instructions].ligne_source,RI[c_instructions].toperande,\
    RI[c_instructions].instruction);//testCT

#endif

  c_instructions += decalage;
  compteur_ligne++;

  }
  while(strcmp(instruction.instruction, "END") && c_instructions < TMEM);
return (nerreurs);
 // return 0;
}
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////


int passe2()
{
  int i;
  //adresse_symbole= -1;

  for( i=0 ; i<TMEM ; i++ )
  {   c_instructions=i;  //pour permettre des calculs avec * en deuxiemme passe
      if((RI[i].oqp ==1)&&(RI[i].instruction>=0))RI[i].operande=obtenir_valeur_operande(RI[i].toperande);  //pb lda# etFCW
   }
  return 0;
}

/*Formats de sortie*/
int ecrire_fichier_echange(FILE *dst)
{
  int i;

  for( i=0; i<TMEM ; i++ )  //calcul de la case memoire a partir des champs  cf 582 double calcul
  {  //dst au lieu de stderr
      if (RI[i].instruction>=0)
    {fprintf( dst,"%ld\n",\
     (long) (( RI[i].instruction << IDECAL ) + RI[i].operande) );
    }
     else if (RI[i].instruction ==FCWT)
     {fprintf( dst,"%ld\n",(long) ( RI[i].operande)) ;
     }
  }
afficher_table_symbole(dst);
  return 0;
}

int ecrire_fichier_listing(FILE * src, FILE *dst)
{
  int compteur_ligne=1, i_instruction, i;
  char ligne[MAX_LINE];

  while(!feof(src))
    {
      fprintf(dst, "%3d ", compteur_ligne);

      for(i_instruction=0; (i_instruction<TMEM) && (RI[i_instruction].ligne_source != compteur_ligne); i_instruction++)
      {
        /*On ne fait rien tant qu'on a pas atteint la bonne instruction*/
      }
      if (RI[i_instruction].ligne_source == compteur_ligne)
      {
        if (RI[i_instruction].instruction >=0)
        {fprintf(dst, "%4d %10ld ", \
          i_instruction,\
          (long) ((RI[i_instruction].instruction << IDECAL) + RI[i_instruction].operande));//attention duplication 556!
        }
        else if (RI[i_instruction].instruction ==FCWT)//////A documenter
        {fprintf(dst, "%4d %10ld ", \
          i_instruction,\
          (long) (RI[i_instruction].operande));//attention duplication 556!
        }
      }
      else
      {
        fprintf(dst, "                ");
      }

      fgets(ligne, MAX_LINE, src);
      for (i=0; i<MAX_LINE; i++)
      {
        if(ligne[i] == '\n')
        {
          ligne[i] = 0;
          break;
        }
      }
      fprintf (dst,"|%s\n",ligne);
      compteur_ligne++;
    }

  afficher_table_symbole(dst);
  return 0;
}

///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////


void usage()
{
        printf("usage : ./assembleur [-i FICHIER] [-o FICHIER] [-m mode]\n");
        printf("  -i FICHIER : lire le source depuis FICHIER (stdin)\n");
        printf("  -o FICHIER : enregistrer la sortie dans FICHIER (stdout)\n");
        printf("  -m mode    : format d'affichage de l'etat de la machine\n");
        printf("     mem : format d'echange avec la machine MVN\n");
        printf("     lst : listing\n");
        printf("  -v : afficher les representations intermediaire sur stderr\n");
        printf("  -h : afficher ce message\n");
}
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////


/**
 * Fonction  principale de l'assembleur
 *
 * Le programme prend en entree un code en langage assembleur et
 * renvoie la memoire correspondante.
 */
int assembler(int argc, char * argv[])
{
  FILE * src = stdin, *dst = stdout;
  extern char *optarg;
  int mode = MODE_MEM, verbose = 0;
  char c;

  initialiser_table_symbole();

  while((c = getopt(argc, argv, "i:o:m:vh")) != EOF)
  {
    switch(c)
    {
      case 'i' :
        if(strcmp(optarg, "-"))
        {
          src = fopen(optarg, "r");
          if ( src == NULL )
          {
            fprintf(stderr,"impossible d'ouvrir le fichier source %s\n", optarg);
            exit(-1);
          }
        }
        break;
      case 'o' :
        if(strcmp(optarg, "-"))
        {
          dst = fopen(optarg, "w");
          if ( dst == NULL )
          {
            fprintf(stderr,"impossible d'ouvrir le fichier de sortie %s\n", optarg);
            exit(-2);
          }
        }
        break;
      case 'm' :
        if(strcmp(optarg, "mem") == 0)
        {
          mode=MODE_MEM;
        }
        if(strcmp(optarg, "lst") == 0)
        {
          mode=MODE_LST;
        }
        break;
      case 'h' :
        usage();
        exit(EXIT_SUCCESS);
        break;
      case 'v' :
        verbose = 1;
        break;
      case '?':
      default :
        usage();
        exit(EXIT_FAILURE);
        break;
    }
  }

  if(src == stdin && optind < argc)
  {
    if(strcmp(argv[optind], "-"))
    {
      src = fopen(argv[optind], "r");
      if ( src == NULL )
      {
        fprintf(stderr,"impossible d'ouvrir le fichier source %s\n", argv[optind]);
        exit(-1);
      }
    }
  }

  passe1(src);

 if(verbose)
  {
  fprintf(stderr, "Passe 1\n");
  afficher_RI(stderr);
  afficher_table_symbole(stderr);
  }

 // ecrire_fichier_listing(src,dst);
  if (nerreurs) {printf("il y a %d erreurs en passe 1\n",nerreurs);
                 return(0);}

  passe2();

  if(verbose)
  {
    fprintf(stderr, "Passe2\n");
    afficher_RI(stderr);
  }

  switch(mode)
  {
    case MODE_MEM:
      ecrire_fichier_echange(dst);
      break;
    case MODE_LST:
      rewind(src);
      ecrire_fichier_listing(src,dst);
      break;
    default:
      ecrire_fichier_echange(dst);
      break;
  }
  fclose(src);
  fclose(dst);
  return 0;
}
